package com.hyt.it.ogt.kq.main.controller.gov;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.StrPool;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.common.apiInfor.DataType;
import com.hyt.common.apiInfor.ParamType;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.progress.BatchGenerateAdmissionTicketLockKeyCreator;
import com.hyt.it.ogt.kq.common.gov.utils.TextUtil;
import com.hyt.it.ogt.kq.main.controller.base.BaseController;
import com.hyt.it.ogt.kq.service.gov.model.entity.Task;
import com.hyt.it.ogt.kq.service.gov.model.entity.TaskRoom;
import com.hyt.it.ogt.kq.service.gov.model.entity.Time;
import com.hyt.it.ogt.kq.service.gov.model.excel.handler.CustomCellWriteHandler;
import com.hyt.it.ogt.kq.service.gov.model.param.ArrangedEditParam;
import com.hyt.it.ogt.kq.service.gov.model.param.DataLockUpdateParam;
import com.hyt.it.ogt.kq.service.gov.model.param.ManualArrangeParam;
import com.hyt.it.ogt.kq.service.gov.model.param.RoomTypeUpdateParam;
import com.hyt.it.ogt.kq.service.gov.model.vo.*;
import com.hyt.it.ogt.kq.service.gov.model.vo.examiner.ProctorArrangeRoomVO;
import com.hyt.it.ogt.kq.service.gov.service.IAsyncService;
import com.hyt.it.ogt.kq.service.gov.service.ITaskService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeRoomCandidateService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeRoomParamService;
import com.hyt.it.ogt.kq.service.gov.service.obs.CloudObsService;
import com.hyt.log.annotation.Log;
import com.hyt.model.PageParam;
import com.hyt.progress.creator.anno.ProgressAnno;
import com.hyt.progress.service.ProgressManager;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

/**
 * <p>
 * 考生编排信息 前端控制器
 * </p>
 *
 * @author huangyh
 * @since 2021-03-08
 */
@Api(tags = "106.编排管理接口", value = "编排管理接口")
@ApiSort(value = 106)
@RestController
@RequestMapping("/kw/gov/timeRoomCandidate")
@Slf4j
public class TimeRoomCandidateController extends BaseController {
    @Resource
    private CloudObsService cloudObsService;
    @Resource
    private ITimeRoomParamService iTimeRoomParamService;

    @Resource
    private ITimeRoomCandidateService iTimeRoomCandidateService;

    @Resource
    private ITaskService iTaskService;

    @Resource
    private IAsyncService iAsyncService;

    @ApiOperation(value = "6.1 考生编排", notes = "30000:考生编排成功; 33001:考生编排异常;")
    @ApiOperationSort(value = 1)
    @PostMapping("/candidateArrange")
    public ApiResponse<ArrangeStatisticsVO> candidateArrange(
            @RequestBody TimeRoomCandidateParamVO timeRoomCandidateParamVO) {
        log.info("考生编排参数: {} ", JSON.toJSONString(timeRoomCandidateParamVO));
        try {
            iTimeRoomCandidateService.candidateArrange(timeRoomCandidateParamVO.getTimeRoomParamVOList(),
                    timeRoomCandidateParamVO.getTaskId(), true);
            ArrangeStatisticsVO arrangeStatistics = iTimeRoomCandidateService
                    .arrangeStatistics(timeRoomCandidateParamVO.getTaskId());
            return ApiResponse.<ArrangeStatisticsVO>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(arrangeStatistics)
                    .build();
        } catch (KqException k) {
            log.error("# 考生编排业务异常: {}", k.getErrMsg());
            return ApiResponse.<ArrangeStatisticsVO>builder()
                    .code(k.getErrCode())
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("编排考生数据失败。", e);
            return ApiResponse.<ArrangeStatisticsVO>builder()
                    .code(ResponseCode.ARRANGE_DATA_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.2 考生增量编排", notes = "30000:考生增量编排成功; 33001:考生增量编排异常;")
    @ApiOperationSort(value = 2)
    @PostMapping("/candidateContinueArrange")
    public ApiResponse<ArrangeStatisticsVO> candidateContinueArrange(
            @RequestBody TimeRoomCandidateParamVO timeRoomCandidateParamVO) {
        ArrangeStatisticsVO arrangeStatistics = null;
        int code = ResponseCode.SUCCESS.getCode();
        try {
            // 校验任务数据锁定状态(后续版本考虑优化为从缓存中获取状态)
            iTaskService.isLockDataThrowException(timeRoomCandidateParamVO.getTaskId());
            iTimeRoomCandidateService.candidateArrange(null, timeRoomCandidateParamVO.getTaskId(), false);
            arrangeStatistics = iTimeRoomCandidateService
                    .arrangeStatistics(timeRoomCandidateParamVO.getTaskId());
        } catch (KqException k) {
            log.error("# 考生增量编排业务异常: {}#{}", k.getErrCode(), k.getErrMsg());
            code = k.getErrCode();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("考生增量考生数据失败。", e);
            code = ResponseCode.ARRANGE_CANDIDATE_INCREMENT_EXCEPTION.getCode();
        }
        return ApiResponse.<ArrangeStatisticsVO>builder().code(code).data(arrangeStatistics).build();
    }

    @ApiOperation(value = "6.3 获取考生编排参数", notes = "30000:获取考生编排参数成功; 33002:获取考生编排参数异常;")
    @ApiOperationSort(value = 3)
    @GetMapping("/getCandidateArrangeParam")
    public ApiResponse<Object> getCandidateArrangeParam(String taskId) {
        try {
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(iTimeRoomParamService.getTaskTimeRoomParam(taskId))
                    .build();
        } catch (Exception e) {
            log.error("查询编排参数异常：", e);
            return ApiResponse.builder()
                    .code(ResponseCode.ARRANGE_GET_PARAM_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.4 预览准考证号", notes = "30000:获取准考证号成功; 33003:获取准考证号异常;")
    @ApiOperationSort(value = 4)
    @PostMapping("/getCandidateAdmission")
    public ApiResponse<Object> getCandidateAdmission(
            @RequestBody TimeRoomCandidateParamVO timeRoomCandidateParamVO) {
        log.info("# 预览准考证号参数: {} ", JSON.toJSONString(timeRoomCandidateParamVO));
        try {
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(iTimeRoomCandidateService.getCandidateAdmission(
                            timeRoomCandidateParamVO.getTimeRoomParamVOList(),
                            timeRoomCandidateParamVO.getTaskId()))
                    .build();
        } catch (KqException k) {
            log.error("# 预览准考证号业务异常: {}", k.getErrMsg());
            return ApiResponse.builder()
                    .code(k.getErrCode())
                    .build();
        } catch (Exception e) {
            log.error("预览准考证号异常：", e);
            return ApiResponse.builder()
                    .code(ResponseCode.ARRANGE_PREVIEW_ACCOUNT_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.5 初始化编排参数", notes = "30000:初始化编排参数成功; 33004:初始化编排参数异常;")
    @ApiOperationSort(value = 5)
    @PostMapping("/initCandidateArrangeParam")
    public ApiResponse<Object> initCandidateArrangeParam(String taskId, String officeId) {

        try {
            iTimeRoomParamService.initTaskTimeRoomParam(taskId, officeId);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (Exception e) {
            log.error("初始化编排参数异常：", e);
            return ApiResponse.builder()
                    .code(ResponseCode.ARRANGE_INIT_PARAM_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.6 查询编排结果", notes = "30000:查询编排结果成功; 33005:查询编排结果异常;")
    @ApiOperationSort(value = 6)
    @GetMapping("/getArrangeCandidate")
    public ApiResponse<Object> getArrangeCandidate(PageParam<TimeRoomCandidateVO> pageParam,
                                                   ArrangeCandidateQueryParamVO arrangeCandidateQueryParamVO) {
        try {
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(iTimeRoomCandidateService.getArrangeCandidate(pageParam,
                            arrangeCandidateQueryParamVO))
                    .build();
        } catch (Exception e) {
            log.error("查询编排结果异常：", e);
            return ApiResponse.builder()
                    .code(ResponseCode.ARRANGE_RESULT_QUERY_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.7 取消编排结果", notes = "30000:取消编排结果成功; 33006:取消编排结果异常;")
    @ApiOperationSort(value = 7)
    @Log(module = "编排管理", business = "删除编排的考生")
    @PutMapping("/removeArrangeCandidate")
    public ApiResponse<Object> removeArrangeCandidate(@RequestBody TimeRoomCandidateParamVO timeRoomCandidateParamVO) {
        try {
            // 校验任务数据锁定状态(后续版本考虑优化为从缓存中获取状态)
            iTaskService.isPublishAndDataLockThrowException(timeRoomCandidateParamVO.getTaskId());
            iTimeRoomCandidateService.removeArrangeCandidate(timeRoomCandidateParamVO.getCandidateIds(), timeRoomCandidateParamVO.getTaskId());
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (KqException k) {
            log.error("# 取消编排结果业务异常: {}", k.getErrMsg());
            return ApiResponse.builder()
                    .code(k.getErrCode())
                    .build();
        } catch (Exception e) {
            log.error("取消编排结果异常：", e);
            return ApiResponse.builder()
                    .code(ResponseCode.ARRANGE_REMOVE_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.8 查询未编排的考生", notes = "30000:查询未编排的考生; 33007:查询未编排的考生异常;")
    @ApiOperationSort(value = 8)
    @GetMapping("/getNoArrangeCandidate")
    public ApiResponse<Object> getNoArrangeCandidate(PageParam<CandidateSubjectNoArrangeVO> pageParam,
                                                     ArrangeNoCandidateQueryParamVO arrangeNoCandidateQueryParamVO) {

        try {
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(iTimeRoomCandidateService.getNoArrangeCandidatePage(pageParam,
                            arrangeNoCandidateQueryParamVO))
                    .build();
        } catch (Exception e) {
            log.error("查询未编排的考生异常：", e);
            return ApiResponse.builder()
                    .code(ResponseCode.ARRANGE_UN_CANDIDATE_QUERY_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.9 导出编排的考生数据", notes = "30000:导出编排的考生数据成功; 33007:导出编排的考生数据异常;")
    @ApiOperationSort(value = 9)
    @GetMapping("/exportArrangeCandidate")
    @ApiImplicitParams({@ApiImplicitParam(name = "taskId", value = "任务id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)})
    @ProgressAnno(total = 100, timeoutSeconds = 60 * 60 * 5)
    public void exportArrangeCandidate(ArrangeCandidateQueryParamVO arrangeCandidateQueryParamVO, String candidateIds) {
        iTimeRoomCandidateService.exportArrangeCandidate(arrangeCandidateQueryParamVO, candidateIds);
    }

    @ApiOperation(value = "6.10 修改锁定状态", notes = "30000:修改锁定状态成功; 30021:修改锁定状态异常; 30022:暂无已编排的考生，无法锁定; 30023:暂未生成基础包，无法锁定")
    @ApiOperationSort(value = 10)
    @Log(module = "编排管理", business = "锁定编排")
    @ProgressAnno(total = 100, timeoutSeconds = 60 * 60 * 5, errorCode = 43061001, canConcurrent = false)
    @PutMapping("/updateTaskDataLock")
    public void updateTaskDataLock(@RequestBody DataLockUpdateParam dataLockUpdateParam) {
        log.info("修改锁定状态参数: {}", dataLockUpdateParam.toString());
        iAsyncService.updateTaskDataLock(dataLockUpdateParam);
    }

    @ApiOperation(value = "6.11 编排统计", notes = "30000:编排统计成功; 30024:编排统计异常;")
    @ApiOperationSort(value = 11)
    @GetMapping("/arrangeStatistics")
    public ApiResponse<ArrangeStatisticsVO> arrangeStatistics(String taskId) {
        log.info("编排统计参数: {}", taskId);
        try {
            ArrangeStatisticsVO arrangeStatistics = iTimeRoomCandidateService.arrangeStatistics(taskId);
            return ApiResponse.<ArrangeStatisticsVO>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(arrangeStatistics)
                    .build();
        } catch (Exception e) {
            log.error("编排统计异常：", e);
            return ApiResponse.<ArrangeStatisticsVO>builder()
                    .code(ResponseCode.ARRANGE_STATISTICS_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.12 导出编排结果DBF", notes = "30000:导出编排结果DBF成功; 30024:导出编排结果DBF异常;")
    @ApiOperationSort(value = 12)
    @GetMapping("/exportArrangeResultDBF")
    public ApiResponse<Object> exportArrangeResultDBF(String taskId) {
        log.info("导出编排结果DBF参数: {}", taskId);
        try {
            iTimeRoomCandidateService.exportArrangeResultDBF(taskId);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (Exception e) {
            log.error("编排统计异常：", e);
            return ApiResponse.builder()
                    .code(ResponseCode.ARRANGE_STATISTICS_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.13 导入兴业编排数据", notes = "30000:导出编排结果DBF成功; 30024:导出编排结果DBF异常;")
    @ApiOperationSort(value = 13)
    @PostMapping("/importTimeRoomCandidate")
    public ApiResponse<Object> importTimeRoomCandidate(@RequestParam String taskId,
                                                       @RequestParam MultipartFile file) {

        log.info("导入兴业编排数据参数: {}", taskId);
        try {
            iTimeRoomCandidateService.importTimeRoomCandidate(taskId, file);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (Exception e) {
            log.error("导入兴业编排数据异常：", e);
            return ApiResponse.builder()
                    .code(ResponseCode.ARRANGE_STATISTICS_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.14 修改锁定状态")
    @ApiOperationSort(value = 14)
    @GetMapping("/updateTaskDataLockStatus")
    public ApiResponse<Object> updateTaskDataLockStatus(@RequestParam String taskId,
                                                        @RequestParam Boolean dataLock) {
        log.info("修改锁定状态参数: {}、{}", taskId, dataLock);
        try {
            iTaskService.lambdaUpdate().set(Task::getDataLock, dataLock).eq(Task::getId, taskId).update();
            return ApiResponse.builder().code(ResponseCode.SUCCESS.getCode()).build();
        } catch (Exception e) {
            log.error("修改锁定状态异常：", e);
            return ApiResponse.builder().code(ResponseCode.UPDATE_TASK_DATA_LOCK_ERROR.getCode()).build();
        }
    }

    @ApiOperation(value = "6.15 推送已编排考生微信通知", notes = "43061501:推送已编排考生微信通知异常; 43061502:推送已编排考生微信通知至报名系统异常")
    @ApiOperationSort(value = 15)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "taskId", value = "考试任务id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
    })
    @GetMapping("/pushWeChatArrangedNotification")
    public ApiResponse<Object> pushWeChatArrangedNotification(@RequestParam String taskId) {
        log.info("# 推送已编排考生微信通知参数: {}", taskId);
        try {
            iTimeRoomCandidateService.pushWeChatArrangedNotification(taskId);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (KqException k) {
            log.error("推送已编排考生微信通知业务异常: {}", k.getErrMsg());
            return ApiResponse.builder()
                    .code(k.getErrCode())
                    .build();
        } catch (Exception e) {
            log.error("推送已编排考生微信通知异常", e);
            return ApiResponse.builder()
                    .code(ResponseCode.PUSH_WECHAT_ARRANGED_NOTIFICATION_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.16 修改编排结果", notes = "43061601:修改编排结果异常; " +
            "43061602:待修改编排结果为空; " +
            "43061603:编排结果将要修改到的目标考场暂无场次数据; " +
            "43061604:编排结果将要修改到的目标考场暂无对应批次; " +
            "43061605:选中的编排数据必须为同一批次下的编排数据; " +
            "43061606:修改编排结果后，以下批次中存在重复考生的编排数据; ")
    @ApiOperationSort(value = 16)
    @PostMapping("/edit")
    public ApiResponse<Object> edit(@Valid @RequestBody ArrangedEditParam arrangedEditParam,
                                    BindingResult bindingResult) {
        log.info("# 修改编排结果参数: {}", JSON.toJSONString(arrangedEditParam));
        try {
            if (bindingResult.hasErrors()) {
                // 修改编排结果参数校验错误
                return ApiResponse.builder()
                        .code(ResponseCode.SUCCESS.getCode())
                        .data(bindingResult.getAllErrors())
                        .build();
            }
            iTimeRoomCandidateService.edit(arrangedEditParam);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (KqException k) {
            log.error("# 修改编排结果业务异常: {}", k.getErrMsg());
            return ApiResponse.builder()
                    .code(k.getErrCode())
                    .data(k.getData())
                    .build();
        } catch (Exception e) {
            log.error("# 修改编排结果异常异常", e);
            return ApiResponse.builder()
                    .code(ResponseCode.ARRANGED_EDIT_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.17 获取批次下绑定的考场信息", notes = "43061701:获取批次下绑定的考场信息异常; ")
    @ApiOperationSort(value = 17)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "taskId", value = "考试任务id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true),
            @ApiImplicitParam(name = "timeId", value = "批次id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
    })
    @GetMapping("/getRoomByTime")
    public ApiResponse<List<TaskRoom>> getRoomByTime(@RequestParam String taskId,
                                                     @RequestParam String timeId,
                                                     @RequestParam(required = false) String deptId,
                                                     @RequestParam(required = false) String areaId,
                                                     @RequestParam(required = false) String searchText) {
        log.info("# 获取批次下绑定的考场信息参数: {}, {}", taskId, timeId);
        try {
            List<TaskRoom> taskRoomList = iTimeRoomCandidateService.getRoomByTime(taskId, timeId, deptId,
                    areaId, searchText);
            return ApiResponse.<List<TaskRoom>>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(taskRoomList)
                    .build();
        } catch (Exception e) {
            log.error("# 获取批次下绑定的考场信息异常", e);
            return ApiResponse.<List<TaskRoom>>builder()
                    .code(ResponseCode.ARRANGED_EDIT_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.18 获取科目下绑定的批次信息", notes = "43061801:获取科目下绑定的批次信息异常; ")
    @ApiOperationSort(value = 18)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "taskId", value = "考试任务id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true),
            @ApiImplicitParam(name = "subjectId", value = "科目id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
    })
    @GetMapping("/getTimeBySubject")
    public ApiResponse<List<Time>> getTimeBySubject(@RequestParam String taskId,
                                                    @RequestParam String subjectId) {
        log.info("# 获取科目下绑定的批次信息参数: {}, {}", taskId, subjectId);
        try {
            List<Time> timeList = iTimeRoomCandidateService.getTimeBySubject(taskId, subjectId);
            return ApiResponse.<List<Time>>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .data(timeList)
                    .build();
        } catch (Exception e) {
            log.error("# 获取科目下绑定的批次信息异常", e);
            return ApiResponse.<List<Time>>builder()
                    .code(ResponseCode.GET_TIME_BY_TASK_SUBJECT_ID_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.19 手动编排", notes = "43061901:手动编排异常; " +
            "43061902:将要编排的考生不存在; " +
            "43061903:将要编排的科目不存在; " +
            "43061904:将要编排的批次不存在; " +
            "43061905:将要编排的考场不存在; " +
            "43061906:将要编排的考生与科目关系不正确; " +
            "43061907:将要编排的考场与批次关系不正确; " +
            "43061908:将要编排的考生已被编排至指定考场、批次、科目中; " +
            "43061909:将要编排的批次与科目关系不正确; ")
    @ApiOperationSort(value = 19)
    @PostMapping("/manualArrange")
    public ApiResponse<Object> manualArrange(@Valid @RequestBody ManualArrangeParam manualArrangeParam,
                                             BindingResult bindingResult) {
        log.info("# 手动编排参数: {}", JSON.toJSONString(manualArrangeParam));
        try {
            if (bindingResult.hasErrors()) {
                // 手动编排参数校验错误
                return ApiResponse.builder()
                        .code(ResponseCode.SUCCESS.getCode())
                        .data(bindingResult.getAllErrors())
                        .build();
            }
            iTimeRoomCandidateService.manualArrange(manualArrangeParam);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (KqException k) {
            log.error("# 手动编排业务异常: {}", k.getErrMsg());
            return ApiResponse.builder()
                    .code(k.getErrCode())
                    .build();
        } catch (Exception e) {
            log.error("# 手动编排异常", e);
            return ApiResponse.builder()
                    .code(ResponseCode.MANUAL_ARRANGE_EXCEPTION.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.20 修改考场类型", notes = "")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "taskId", value = "考试任务id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true),
            @ApiImplicitParam(name = "roomType", value = "考场类型，0：虚拟考场，1：实体考场，2：自定义考场", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
    })
    @ApiOperationSort(value = 20)
    @PutMapping("/updateTimeRoomCandidateParamRoomType")
    public ApiResponse<Object> updateTimeRoomCandidateParamRoomType(
            @RequestBody RoomTypeUpdateParam roomTypeUpdateParam) {
        log.info("# 修改考场类型参数: {}", JSON.toJSONString(roomTypeUpdateParam));
        try {
            iTimeRoomParamService.updateTaskTimeRoomParamRoomType(roomTypeUpdateParam);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (KqException k) {
            log.error("修改考场类型异常: {}", k.getErrMsg());
            return ApiResponse.builder()
                    .code(k.getErrCode())
                    .data(k.getErrMsg())
                    .build();
        } catch (Exception e) {
            log.error("修改考场类型异常", e);
            return ApiResponse.builder()
                    .code(ResponseCode.UPDATE_TIME_ROOM_CANDIDATE_PARAM_ROOM_TYPE.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "6.99 增量添加/修改考生编排数据(无限权限)", notes = "导入的所有考生，都会将之前的所有考生数据删除，包括编排数据，甚至是推送到考试的数据。")
    @ApiOperationSort(value = 99)
    @PutMapping("/addOrUpdateCandidate")
    public ApiResponse<Object> addOrUpdateCandidate(@RequestParam String taskId, @RequestParam MultipartFile file) {
        try {
            iTimeRoomCandidateService.addOrUpdateCandidate(taskId, file);
            return ApiResponse.builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .build();
        } catch (KqException k) {
            log.error("增量添加/修改考生编排数据(无限权限)异常: {}", k.getErrMsg());
            return ApiResponse.builder()
                    .code(k.getErrCode())
                    .data(k.getErrMsg())
                    .build();
        } catch (Exception e) {
            log.error("增量添加/修改考生编排数据(无限权限)异常", e);
            return ApiResponse.builder()
                    .code(ResponseCode.UPDATE_TIME_ROOM_CANDIDATE_PARAM_ROOM.getCode())
                    .build();
        }
    }

}
